package com.lemon.springcloud.core.spring.factory;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.lemon.core.common.lang.util.StringUtils;
import com.lemon.springcloud.core.bean.ServiceInfo;
import com.lemon.springcloud.core.component.elasticsearch.ElasticsearchTool;
import com.lemon.springcloud.core.component.mybatis.DataSourceDefaultVal;
import com.lemon.springcloud.core.component.rabbitmq.RabbitMQ;
import com.lemon.springcloud.core.component.redis.RedisCache;
import com.lemon.springcloud.core.component.zookeeper.ZkBoot;
import com.lemon.springcloud.core.config.LemonSpringBootConfig;
import com.lemon.springcloud.core.initial.LemonApplicationInitializer;
import com.lemon.springcloud.core.util.PropertiesUtils;
import com.lemon.springcloud.core.util.RegisterComponentInfoUtils;
import com.mop.core.es.dao.dao.impl.ElasticSearchDao;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.ClassPathMapperScanner;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.*;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;

/**
 * @author hdzhang
 * @ClassName CoreBeanPostProcessor
 * @desc
 * @Date 2018/9/7 20:11
 * @Version 1.0
 **/
public class CoreBeanPostProcessor implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanDefinitionRegistryPostProcessor, EnvironmentAware {

    /**
     * db name set
     */
    private Set<String> dbNameSet = new HashSet<String>();

    /**
     * datasource config
     */
    private Map<String, String> dataSourceConfigMap = new HashMap<String, String>();

    /**
     * redis name set
     */
    private Set<String> redisNameSet = new HashSet<String>();

    /**
     * redis config
     */
    private Map<String, String> redisConfigMap = new HashMap<String, String>();

    /**
     * rabbitmq name set
     */
    private Set<String> rabbitMqNameSet = new HashSet<String>();

    /**
     * rabbitmq config
     */
    private Map<String, String> rabbitMqConfigMap = new HashMap<String, String>();

    /**
     * zookeeper name set
     */
    private Set<String> zookeeperNameSet = new HashSet<String>();

    /**
     * zookeeper cnfig
     */
    private Map<String, String> zookeeperConfigMap = new HashMap<String, String>();

    /**
     * elasticsearch name set
     */
    private Set<String> elasticsearchNameSet = new HashSet<String>();

    /**
     * elasticsearch cnfig
     */
    private Map<String, String> elasticsearchConfigMap = new HashMap<String, String>();

    /**
     * resourceLoader
     */
    private ResourceLoader resourceLoader;

    /**
     * env
     */
    private Environment env;

    @Override
    public void setEnvironment(Environment environment) {
        this.env = environment;
        List<PropertySource> applicationConfigurationPropertiesSource = new LinkedList<>();
        PropertySource<?> applicationConfigurationProperties = ((ConfigurableEnvironment) environment).getPropertySources()
                .get("applicationConfigurationProperties");
        if (applicationConfigurationProperties == null) {
            applicationConfigurationProperties = ((ConfigurableEnvironment) environment).getPropertySources()
                    .get("applicationConfig: [classpath:/application.properties]");
            applicationConfigurationPropertiesSource.add(applicationConfigurationProperties);
        } else {
            applicationConfigurationPropertiesSource.add(applicationConfigurationProperties);
        }

        if (applicationConfigurationProperties == null) {
            return;
        }

        if (applicationConfigurationPropertiesSource == null) {
            return;
        }
        for (PropertySource propertySource : applicationConfigurationPropertiesSource) {
            if (propertySource.getSource() instanceof Set) {
                Set sourceSet = (Set) propertySource.getSource();
                if (sourceSet == null) {
                    continue;
                }

                for (Object o : sourceSet) {
                    if (o instanceof MapPropertySource) {
                        Map<String, Object> properties = ((MapPropertySource) o).getSource();
                        for (String key : properties.keySet()) {
                            readDatasourceConfig(properties, key);
                            readRedisConfig(properties, key);
                            readRabbitMqConfig(properties, key);
                            readZookeeperConfig(properties, key);
                            readElasticsearchConfig(properties, key);
                        }
                    }
                }
            } else if (propertySource.getSource() instanceof LinkedHashMap) {
                LinkedHashMap hashMap = (LinkedHashMap) propertySource.getSource();
                if (hashMap == null) {
                    continue;
                }
                for (Object key : hashMap.keySet()) {
                    readDatasourceConfig(hashMap, key.toString());
                    readRedisConfig(hashMap, key.toString());
                    readRabbitMqConfig(hashMap, key.toString());
                    readZookeeperConfig(hashMap, key.toString());
                    readElasticsearchConfig(hashMap, key.toString());
                }
            } else if (propertySource.getSource() instanceof Map) {
                Map map = (Map) propertySource.getSource();
                if (map == null) {
                    continue;
                }
                for (Object key : map.keySet()) {
                    readDatasourceConfig(map, key.toString());
                    readRedisConfig(map, key.toString());
                    readRabbitMqConfig(map, key.toString());
                    readZookeeperConfig(map, key.toString());
                    readElasticsearchConfig(map, key.toString());
                }
            }
        }
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;

        if (LemonApplicationInitializer.getLemonBuildMybatisEnable()) {
            // bean 注入
            /*BeanDefinitionBuilder dataSourceBean = BeanDefinitionBuilder.rootBeanDefinition(DruidDataSource.class.getName());
            dataSourceBean.addPropertyValue("connectionProperties", datasourceConfigMap.get(prefix + "datasource.connectionProperties"));
            defaultListableBeanFactory.registerBeanDefinition(dbName + "DataSource", dataSourceBean.getBeanDefinition());*/
        }

        if (LemonApplicationInitializer.getLemonBuildRedisEnable()) {

        }

        if (LemonApplicationInitializer.getLemonBuildRabbitMQEnable()) {

        }
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        if (LemonApplicationInitializer.getLemonBuildMybatisEnable()) {
            // 向context注入mabtis和datasource
            this.registerDatasource(registry);
        }

        if (LemonApplicationInitializer.getLemonBuildRedisEnable()) {
            // 向context注入redis
            registerRedis(registry);
        }

        if (LemonApplicationInitializer.getLemonBuildRabbitMQEnable()) {
            // 向context注入rabbitmq
            registerRabbitMq(registry);
        }

        if (LemonApplicationInitializer.getLemonBuildInZkEnable()) {
            registerZookeeper(registry);
        }

        if (LemonApplicationInitializer.getLemonBuildInEsEnable()) {
            registerElasticsearch(registry);
        }

        //registerMonitor(registry);
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

    }

    /**
     * datasource 配置读取
     * @param properties
     * @param key
     */
    private void readDatasourceConfig(Map<String, Object> properties, String key) {
        String redisConfigPrefix = "lemon.db.";
        if (key.contains(redisConfigPrefix)) {
            dataSourceConfigMap.put(key, String.valueOf(properties.get(key)));
            dbNameSet.add(key.replace(redisConfigPrefix, "").substring(0, key.replace(redisConfigPrefix, "").indexOf(".")));
        }
    }

    /**
     * redis 配置读取
     * @param properties
     * @param key
     */
    private void readRedisConfig(Map<String, Object> properties, String key) {
        String redisConfigPrefix = "lemon.redis.";
        if (key.contains(redisConfigPrefix)) {
            redisConfigMap.put(key, String.valueOf(properties.get(key)));
            redisNameSet.add(key.replace(redisConfigPrefix, "").substring(0, key.replace(redisConfigPrefix, "").indexOf(".")));
        }
    }

    /**
     * rabbitmq 配置读取
     * @param properties
     * @param key
     */
    private void readRabbitMqConfig(Map<String, Object> properties, String key) {
        String redisConfigPrefix = "lemon.rabbitmq.";
        if (key.contains(redisConfigPrefix)) {
            rabbitMqConfigMap.put(key, String.valueOf(properties.get(key)));
            rabbitMqNameSet.add(key.replace(redisConfigPrefix, "").substring(0, key.replace(redisConfigPrefix, "").indexOf(".")));
        }
    }

    /**
     * zookeeper 配置读取
     * @param properties
     * @param key
     */
    private void readZookeeperConfig(Map<String,Object> properties, String key) {
        String zookeeperConfigPrefix = "lemon.zookeeper.";
        if (key.contains(zookeeperConfigPrefix)) {
            if (key.contains("conf.properties")) {
                return;
            }
            zookeeperConfigMap.put(key, String.valueOf(properties.get(key)));
            zookeeperNameSet.add(key.replace(zookeeperConfigPrefix, "").substring(0, key.replace(zookeeperConfigPrefix, "").indexOf(".")));
        }
    }

    /**
     * elasticsearch 配置读取
     * @param properties
     * @param key
     */
    private void readElasticsearchConfig(Map<String,Object> properties, String key) {
        String zookeeperConfigPrefix = "lemon.es.";
        if (key.contains(zookeeperConfigPrefix)) {
            elasticsearchConfigMap.put(key, String.valueOf(properties.get(key)));
            elasticsearchNameSet.add(key.replace(zookeeperConfigPrefix, "").substring(0, key.replace(zookeeperConfigPrefix, "").indexOf(".")));
        }
    }

    /**
     * 注册 datasource
     * @param registry
     */
    private void registerDatasource(BeanDefinitionRegistry registry) {
        String prefixKey = "lemon.db.";
        if (dataSourceConfigMap.isEmpty()) {
            Set<String> keySet = PropertiesUtils.getPrefixSigns(prefixKey);
            Iterator keyItor = keySet.iterator();
            while (keyItor.hasNext()) {
                // mybatis config
                String key = keyItor.next().toString();
                dbNameSet.add(key);
                String configFilePath = prefixKey + key + ".mybatis.config-file-path";
                String mapperLocations = prefixKey + key + ".mybatis.mapper-locations";
                String mapperBasePackage = prefixKey + key + ".mybatis.mapper-base-package";
                String typeAliasesPackage = prefixKey + key + ".mybatis.type-aliases-package";

                // datasource config
                String driverClassName = prefixKey + key + ".datasource.driverClassName";
                String url = prefixKey + key + ".datasource.url";
                String username = prefixKey + key + ".datasource.username";
                String password = prefixKey + key + ".datasource.password";
                String initialSize = prefixKey + key + ".datasource.initialSize";
                String minIdle = prefixKey + key + ".datasource.minIdle";
                String maxActive = prefixKey + key + ".datasource.maxActive";
                String maxWait = prefixKey + key + ".datasource.maxWait";
                String validationQuery = prefixKey + key + ".datasource.validationQuery";
                String maxPoolPreparedStatementPerConnectionSize = prefixKey + key + ".datasource.maxPoolPreparedStatementPerConnectionSize";
                String filters = prefixKey + key + ".datasource.filters";
                String connectionProperties = prefixKey + key + ".datasource.connectionProperties";

                // mybatis 设置值
                dataSourceConfigMap.put(configFilePath, PropertiesUtils.getString(configFilePath));
                dataSourceConfigMap.put(mapperLocations, PropertiesUtils.getString(mapperLocations));
                dataSourceConfigMap.put(mapperBasePackage, PropertiesUtils.getString(mapperBasePackage));
                dataSourceConfigMap.put(typeAliasesPackage, PropertiesUtils.getString(typeAliasesPackage));

                // datasource 设置值
                dataSourceConfigMap.put(driverClassName, PropertiesUtils.getString(driverClassName));
                dataSourceConfigMap.put(url, PropertiesUtils.getString(url));
                dataSourceConfigMap.put(username, PropertiesUtils.getString(username));
                dataSourceConfigMap.put(password, PropertiesUtils.getString(password));
                dataSourceConfigMap.put(initialSize, StringUtils.isBlank(
                        PropertiesUtils.getString(initialSize)) ? DataSourceDefaultVal.initialSize : PropertiesUtils.getString(initialSize));
                dataSourceConfigMap.put(minIdle, StringUtils.isBlank(
                        PropertiesUtils.getString(minIdle)) ? DataSourceDefaultVal.minIdle : PropertiesUtils.getString(minIdle));
                dataSourceConfigMap.put(maxActive, StringUtils.isBlank(
                        PropertiesUtils.getString(maxActive)) ? DataSourceDefaultVal.maxActive : PropertiesUtils.getString(maxActive));
                dataSourceConfigMap.put(maxWait, StringUtils.isBlank(
                        PropertiesUtils.getString(maxWait)) ? DataSourceDefaultVal.maxWait : PropertiesUtils.getString(maxWait));
                dataSourceConfigMap.put(validationQuery, StringUtils.isBlank(
                        PropertiesUtils.getString(validationQuery)) ? DataSourceDefaultVal.validationQueryMySql : PropertiesUtils.getString(validationQuery));
                dataSourceConfigMap.put(maxPoolPreparedStatementPerConnectionSize, StringUtils.isBlank(
                        PropertiesUtils.getString(maxPoolPreparedStatementPerConnectionSize)) ? DataSourceDefaultVal.maxPoolPreparedStatementPerConnectionSize : PropertiesUtils.getString(maxPoolPreparedStatementPerConnectionSize));
                dataSourceConfigMap.put(filters, StringUtils.isBlank(
                        PropertiesUtils.getString(filters)) ? DataSourceDefaultVal.filters : PropertiesUtils.getString(filters));
                dataSourceConfigMap.put(connectionProperties, StringUtils.isBlank(
                        PropertiesUtils.getString(connectionProperties)) ? DataSourceDefaultVal.connectionProperties : PropertiesUtils.getString(connectionProperties));
            }
        }


        Iterator<String> iterator = dbNameSet.iterator();
        while (iterator.hasNext()) {
            String dbName = iterator.next();
            String prefix = "lemon.db." + dbName + ".";

            RootBeanDefinition dataSourceBean = new RootBeanDefinition();
            dataSourceBean.setBeanClass(DruidDataSource.class);
            // 需要注入的参数，类似spring配置文件中的<property/>
            MutablePropertyValues mpv = dataSourceBean.getPropertyValues();
            // 注入值
            mpv.add("driverClassName", dataSourceConfigMap.get(prefix + "datasource.driverClassName"));
            mpv.add("url", dataSourceConfigMap.get(prefix + "datasource.url"));
            mpv.add("username", dataSourceConfigMap.get(prefix + "datasource.username"));
            mpv.add("password", dataSourceConfigMap.get(prefix + "datasource.password"));
            mpv.add("initialSize", Integer.parseInt(
                    StringUtils.isBlank(dataSourceConfigMap.get(prefix + "datasource.initialSize")) ? DataSourceDefaultVal.initialSize : dataSourceConfigMap.get(prefix + "datasource.initialSize")
            ));
            mpv.add("minIdle", Integer.parseInt(
                    StringUtils.isBlank(dataSourceConfigMap.get(prefix + "datasource.minIdle")) ? DataSourceDefaultVal.minIdle : dataSourceConfigMap.get(prefix + "datasource.minIdle")));
            mpv.add("maxActive", Integer.parseInt(
                    StringUtils.isBlank(dataSourceConfigMap.get(prefix + "datasource.maxActive")) ? DataSourceDefaultVal.maxActive : dataSourceConfigMap.get(prefix + "datasource.maxActive")));
            mpv.add("maxWait", Long.parseLong(
                    StringUtils.isBlank(dataSourceConfigMap.get(prefix + "datasource.maxWait")) ? DataSourceDefaultVal.maxWait : dataSourceConfigMap.get(prefix + "datasource.maxWait")));
            mpv.add("validationQuery",
                    StringUtils.isBlank(dataSourceConfigMap.get(prefix + "datasource.validationQuery")) ? DataSourceDefaultVal.validationQueryMySql : dataSourceConfigMap.get(prefix + "datasource.validationQuery"));
            mpv.add("maxPoolPreparedStatementPerConnectionSize", Integer.parseInt(
                    StringUtils.isBlank(dataSourceConfigMap.get(prefix + "datasource.maxPoolPreparedStatementPerConnectionSize")) ? DataSourceDefaultVal.maxPoolPreparedStatementPerConnectionSize : dataSourceConfigMap.get(prefix + "datasource.maxPoolPreparedStatementPerConnectionSize")));
            mpv.add("filters",
                    StringUtils.isBlank(dataSourceConfigMap.get(prefix + "datasource.filters")) ? DataSourceDefaultVal.filters : dataSourceConfigMap.get(prefix + "datasource.filters"));
            mpv.add("connectionProperties",
                    StringUtils.isBlank(dataSourceConfigMap.get(prefix + "datasource.connectionProperties")) ? DataSourceDefaultVal.connectionProperties : dataSourceConfigMap.get(prefix + "datasource.connectionProperties"));
            if ("default".equals(dbName)) {
                dataSourceBean.setPrimary(true);
            }
            registry.registerBeanDefinition(dbName + "dataSource", dataSourceBean);

            // 添加打印信息
            String protocol = dataSourceConfigMap.get(prefix + "datasource.username") + "/"
                    + dataSourceConfigMap.get(prefix + "datasource.password") + "@"
                    + dataSourceConfigMap.get(prefix + "datasource.url");
            LemonSpringBootConfig.addMybatisGroupInfo("mybatis." + dbName, protocol);

            // 注入 SessionFactory
            RootBeanDefinition sessionFactoryBean = new RootBeanDefinition();
            sessionFactoryBean.setBeanClass(MybatisSqlSessionFactoryBean.class);
            mpv = sessionFactoryBean.getPropertyValues();
            /*mpv.add("mapperLocations", new PathMatchingResourcePatternResolver()
                    .getResource(dataSourceConfigMap.get(prefix + "mybatis.mapper-locations")));*/
            mpv.add("dataSource", dataSourceBean);
            mpv.add("typeAliasesPackage", dataSourceConfigMap.get(prefix + "mybatis-plus.type-aliases-package"));
            registry.registerBeanDefinition(dbName + "SessionFactory", sessionFactoryBean);

            // 注入 sqltemplate
            RootBeanDefinition sqlSessionTemplateBean = new RootBeanDefinition();
            sqlSessionTemplateBean.setBeanClass(SqlSessionTemplate.class);
            ConstructorArgumentValues constructorArgs = new ConstructorArgumentValues();
            constructorArgs.addIndexedArgumentValue(0, sessionFactoryBean);
            sqlSessionTemplateBean.setConstructorArgumentValues(constructorArgs);
            registry.registerBeanDefinition(dbName + "SessionTemplate", sqlSessionTemplateBean);

            // 注入 DataSourceTransactionManager
            RootBeanDefinition transactionManagerBean = new RootBeanDefinition();
            transactionManagerBean.setBeanClass(DataSourceTransactionManager.class);
            mpv = transactionManagerBean.getPropertyValues();
            mpv.add("dataSource", dataSourceBean);
            //registry.registerBeanDefinition(dbName + "TransactionManager", transactionManagerBean);


            // 动态指定扫描路径
            ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
            if (resourceLoader != null) { // this check is needed in Spring 3.1
                scanner.setResourceLoader(resourceLoader);
            }
            scanner.setSqlSessionFactoryBeanName(dbName + "SessionFactory");
            scanner.setSqlSessionTemplateBeanName(dbName + "SessionTemplate");
            scanner.registerFilters();
            scanner.doScan(dataSourceConfigMap.get(prefix + "mybatis.mapper-base-package").split(","));

            // 注入 PaginationInterceptor
            RootBeanDefinition paginationBean = new RootBeanDefinition();
            paginationBean.setBeanClass(PaginationInterceptor.class);
            mpv = paginationBean.getPropertyValues();
            //mpv.add("localPage", true);
            mpv.add("dialectType", "mysql");
            registry.registerBeanDefinition(dbName + "PaginationInterceptor", paginationBean);

            // 注入 PerformanceInterceptor
            RootBeanDefinition performanceBean = new RootBeanDefinition();
            performanceBean.setBeanClass(PerformanceInterceptor.class);
            mpv = performanceBean.getPropertyValues();
            mpv.add("maxTime", 1000);
            mpv.add("format", true);
            registry.registerBeanDefinition(dbName + "PerformanceInterceptor", performanceBean);
        }
    }

    /**
     * 注册 redis
     * @param registry
     */
    private void registerRedis(BeanDefinitionRegistry registry) {
        if (redisConfigMap.isEmpty()) {
            String prefixKey = "lemon.redis.";
            Set<String> keySet = PropertiesUtils.getPrefixSigns(prefixKey);
            Iterator keyItor = keySet.iterator();
            while (keyItor.hasNext()) {
                String key = keyItor.next().toString();
                redisNameSet.add(key);
                String hostName = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".host";
                String port = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".port";
                String password = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".password";

                redisConfigMap.put(prefixKey + key + ".host", PropertiesUtils.getString(hostName));
                redisConfigMap.put(prefixKey + key + ".port", PropertiesUtils.getString(port));
                redisConfigMap.put(prefixKey + key + ".password", PropertiesUtils.getString(password));
            }
        }

        Iterator<String> iterator = redisNameSet.iterator();
        while (iterator.hasNext()) {
            String redisName = iterator.next();
            String prefix = "lemon.redis." + redisName + ".";

            String redisGroupName = "redis." + redisName;
            String host = redisConfigMap.get(prefix + "host");
            Integer port = Integer.valueOf(redisConfigMap.get(prefix + "port"));
            String password = redisConfigMap.get(prefix + "password");
            RegisterComponentInfoUtils.registerRedisInfo(redisGroupName, host, port, password);

            RootBeanDefinition redisBean = new RootBeanDefinition();
            redisBean.setBeanClass(RedisCache.class);
            ConstructorArgumentValues cavs = new ConstructorArgumentValues();
            cavs.addIndexedArgumentValue(0, redisConfigMap.get(prefix + "host"));
            cavs.addIndexedArgumentValue(1, redisConfigMap.get(prefix + "port"));
            cavs.addIndexedArgumentValue(2, redisConfigMap.get(prefix + "password"));
            redisBean.setConstructorArgumentValues(cavs);
            registry.registerBeanDefinition(redisName + "RedisCache", redisBean);
        }
    }

    /**
     * 注册 rabbitmq
     * @param registry
     */
    private void registerRabbitMq(BeanDefinitionRegistry registry) {
        if (rabbitMqConfigMap.isEmpty()) {
            String prefixKey = "lemon.rabbitmq.";
            Set<String> keySet = PropertiesUtils.getPrefixSigns(prefixKey);
            Iterator keyItor = keySet.iterator();
            while (keyItor.hasNext()) {
                String key = keyItor.next().toString();
                rabbitMqNameSet.add(key);
                String host = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".host";
                String port = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".port";
                String username = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".username";
                String password = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".password";

                rabbitMqConfigMap.put(prefixKey + key + ".host", PropertiesUtils.getString(host));
                rabbitMqConfigMap.put(prefixKey + key + ".port", PropertiesUtils.getString(port));
                rabbitMqConfigMap.put(prefixKey + key + ".username", PropertiesUtils.getString(username));
                rabbitMqConfigMap.put(prefixKey + key + ".password", PropertiesUtils.getString(password));
            }
        }

        Iterator<String> iterator = rabbitMqNameSet.iterator();
        while (iterator.hasNext()) {
            String rabbitmqName = iterator.next();
            String prefix = "lemon.rabbitmq." + rabbitmqName + ".";

            String rabbitmqGroupName =  "rabbitmq." + rabbitmqName;
            String host = rabbitMqConfigMap.get(prefix + "host");
            Integer port = Integer.valueOf(rabbitMqConfigMap.get(prefix + "port"));
            String username = rabbitMqConfigMap.get(prefix + "username");
            String password = rabbitMqConfigMap.get(prefix + "password");
            String virtualHost = "/";
            RegisterComponentInfoUtils.registerRabbitMQInfo(rabbitmqGroupName, host, port, username, password);

            RootBeanDefinition rabbitmqBean = new RootBeanDefinition();
            rabbitmqBean.setBeanClass(RabbitMQ.class);
            ConstructorArgumentValues cavs = new ConstructorArgumentValues();
            cavs.addIndexedArgumentValue(0, host);
            cavs.addIndexedArgumentValue(1, port);
            cavs.addIndexedArgumentValue(2, username);
            cavs.addIndexedArgumentValue(3, password);
            cavs.addIndexedArgumentValue(4, virtualHost);
            rabbitmqBean.setConstructorArgumentValues(cavs);
            registry.registerBeanDefinition(rabbitmqName + "RabbitMQ", rabbitmqBean);

            // 注入 connectionFactory
            RootBeanDefinition connectionFactoryBean = new RootBeanDefinition();
            connectionFactoryBean.setBeanClass(CachingConnectionFactory.class);
            // 需要注入的参数，类似spring配置文件中的<property/>
            MutablePropertyValues mpv = connectionFactoryBean.getPropertyValues();
            // 注入值
            mpv.add("host", host);
            mpv.add("port", port);
            mpv.add("username", username);
            mpv.add("password", password);
            mpv.add("publisherConfirms", true);
            mpv.add("virtualHost", virtualHost);
            registry.registerBeanDefinition("connectionFactory", connectionFactoryBean);
        }
    }

    /**
     * 注册 zookeeper
     * @param registry
     */
    private void registerZookeeper(BeanDefinitionRegistry registry) {
        if (zookeeperConfigMap.isEmpty()) {
            String prefixKey = "lemon.zookeeper.";
            Set<String> keySet = PropertiesUtils.getPrefixSigns(prefixKey);
            Iterator keyItor = keySet.iterator();
            while (keyItor.hasNext()) {
                String key = keyItor.next().toString();
                zookeeperNameSet.add(key);
                String host = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".host";
                String port = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".port";

                zookeeperConfigMap.put(prefixKey + key + ".host", PropertiesUtils.getString(host));
                zookeeperConfigMap.put(prefixKey + key + ".port", PropertiesUtils.getString(port));
            }
        }

        Iterator<String> iterator = zookeeperNameSet.iterator();
        while (iterator.hasNext()) {
            String zookeeperName = iterator.next();
            if ("conf".equals(zookeeperName)) {
                continue;
            }
            String prefix = "lemon.zookeeper." + zookeeperName + ".";

            RootBeanDefinition zookeeperBean = new RootBeanDefinition();
            zookeeperBean.setBeanClass(ZkBoot.class);
            ConstructorArgumentValues cavs = new ConstructorArgumentValues();
            cavs.addIndexedArgumentValue(0, "zookeeper." + zookeeperName);
            cavs.addIndexedArgumentValue(1, zookeeperConfigMap.get(prefix + "host"));
            cavs.addIndexedArgumentValue(2, zookeeperConfigMap.get(prefix + "port"));
            zookeeperBean.setConstructorArgumentValues(cavs);
            registry.registerBeanDefinition(zookeeperName + "ZK", zookeeperBean);
        }
    }

    /**
     * 注册 elasticsearch
     * @param registry
     */
    private void registerElasticsearch(BeanDefinitionRegistry registry) {
        if (elasticsearchConfigMap.isEmpty()) {
            String prefixKey = "lemon.es.";
            Set<String> keySet = PropertiesUtils.getPrefixSigns(prefixKey);
            Iterator keyItor = keySet.iterator();
            while (keyItor.hasNext()) {
                String key = keyItor.next().toString();
                elasticsearchNameSet.add(key);
                String httpUrls = prefixKey + key + "." + ServiceInfo.ENV_NAME + ".http.urls";

                elasticsearchConfigMap.put(prefixKey + key + ".http.urls", PropertiesUtils.getString(httpUrls));
            }
        }

        Iterator<String> iterator = elasticsearchNameSet.iterator();
        while (iterator.hasNext()) {
            String elasticsearchName = iterator.next();
            String prefix = "lemon.es." + elasticsearchName + ".";

            String elasticsearchGroupName = "elasticsearch." + elasticsearchName;
            String httpUrls = elasticsearchConfigMap.get(prefix + "http.urls");
            List<String> serverUris = Arrays.asList(httpUrls.replaceAll(" ", "").split(","));

            RegisterComponentInfoUtils.registerElasticsearchMQInfo(elasticsearchGroupName, serverUris);

            RootBeanDefinition elasticsearchBean = new RootBeanDefinition();
            elasticsearchBean.setBeanClass(ElasticsearchTool.class);
            ConstructorArgumentValues cavs = new ConstructorArgumentValues();
            cavs.addIndexedArgumentValue(0, serverUris);
            elasticsearchBean.setConstructorArgumentValues(cavs);
            registry.registerBeanDefinition(elasticsearchName + "ElasticsearchTool", elasticsearchBean);
        }
    }

    private void registerMonitor(BeanDefinitionRegistry registry) {
        try {
            RootBeanDefinition serverBean = new RootBeanDefinition();
            serverBean.setBeanClass(ServerProperties.class);
            MutablePropertyValues mpv = serverBean.getPropertyValues();
            mpv.add("address", InetAddress.getByName("172.18.33.39"));
            mpv.add("port", 15001);
            registry.registerBeanDefinition("serverProperties", serverBean);

            RootBeanDefinition eurekaInstanceConfigBean = new RootBeanDefinition();
            eurekaInstanceConfigBean.setBeanClass(EurekaInstanceConfigBean.class);
            mpv = eurekaInstanceConfigBean.getPropertyValues();
            mpv.add("ipAddress", "172.18.33.39");
            mpv.add("hostname", "172.18.33.39");
            registry.registerBeanDefinition("eurekaInstanceConfigBean", eurekaInstanceConfigBean);

            RootBeanDefinition eurekaClientConfigBean = new RootBeanDefinition();
            eurekaClientConfigBean.setBeanClass(EurekaClientConfigBean.class);
            mpv = eurekaClientConfigBean.getPropertyValues();
            mpv.add("serviceUrl", "${EUREKA_SERVICE_URL:http://172.18.254.28:16000}/eureka/");
            registry.registerBeanDefinition("eurekaClientConfigBean", eurekaClientConfigBean);

            /*RootBeanDefinition webEndpointProperties = new RootBeanDefinition();
            webEndpointProperties.setBeanClass(WebEndpointProperties.class);
            mpv = webEndpointProperties.getPropertyValues();
            mpv.add("include", "*");
            registry.registerBeanDefinition("webEndpointProperties", webEndpointProperties);*/
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}
